﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Snowdreamist.ComponentModel
{
    public class ReadWriteCriticalRegion : CriticalDisposableObject
    {
        public ReadWriteCriticalRegion()
        {
            this._rwLock = new ReaderWriterLockSlim();
        }

        public ReadWriteCriticalRegion(LockRecursionPolicy policy)
        {
            this._rwLock = new ReaderWriterLockSlim(policy);
        }

        public CriticalDisposableObject EnterReadRegion()
        {
            return new SingleReadWriteCriticalRegion(this, r => r._rwLock.EnterReadLock(), r => r._rwLock.ExitReadLock());
        }

        public CriticalDisposableObject EnterWriteRegion()
        {
            return new SingleReadWriteCriticalRegion(this, r => r._rwLock.EnterWriteLock(), r => r._rwLock.ExitWriteLock());
        }

        public CriticalDisposableObject EnterUpgradeableReadRegion()
        {
            return new SingleReadWriteCriticalRegion(this, r => r._rwLock.EnterUpgradeableReadLock(), r => r._rwLock.ExitUpgradeableReadLock());
        }

        protected override void DisposeOnce()
        {
            this._rwLock.Dispose();
        }

        #region private

        private class SingleReadWriteCriticalRegion : CriticalDisposableObject
        {
            public SingleReadWriteCriticalRegion(ReadWriteCriticalRegion region, Action<ReadWriteCriticalRegion> lockAction, Action<ReadWriteCriticalRegion> unlockAction)
            {
                this._region = region;
                lockAction(region);
                this._unlockAction = unlockAction;
            }

            protected override void DisposeOnce()
            {
                this._unlockAction(this._region);
            }

            private ReadWriteCriticalRegion _region;

            private Action<ReadWriteCriticalRegion> _unlockAction;
        }

        private ReaderWriterLockSlim _rwLock;

        #endregion
    }
}
